<?php
namespace app\middleware;

use Webman\MiddlewareInterface;
use Webman\Http\Response;
use Webman\Http\Request;
use app\model\AdminOperationLogModel;

class AdminOperationLog implements MiddlewareInterface
{
    // 不需要记录日志的路由
    protected $except = [
        'admin/auth/login',
        'admin/auth/logout',
        'admin/operation-log/*',  // 不记录日志查看操作
        'admin/*/index',  // 不记录列表查看
        'admin/*/show',   // 不记录详情查看
    ];
    
    // 敏感操作路由及其描述
    protected $sensitiveOperations = [
        // 管理员相关
        'POST@admin/admins' => '创建管理员',
        'PUT@admin/admins/*' => '更新管理员信息',
        'DELETE@admin/admins/*' => '删除管理员',
        'POST@admin/admins/*/roles' => '分配管理员角色',
        
        // 角色相关
        'POST@admin/admin-roles' => '创建角色',
        'PUT@admin/admin-roles/*' => '更新角色信息',
        'DELETE@admin/admin-roles/*' => '删除角色',
        'POST@admin/admin-roles/*/permissions' => '分配角色权限',
        
        // 权限相关
        'POST@admin/admin-permissions' => '创建权限',
        'PUT@admin/admin-permissions/*' => '更新权限信息',
        'DELETE@admin/admin-permissions/*' => '删除权限',
        
        // 文章分类相关
        'POST@admin/article-categories' => '创建文章分类',
        'PUT@admin/article-categories/*' => '更新文章分类',
        'DELETE@admin/article-categories/*' => '删除文章分类',
        
        // 文章标签相关
        'POST@admin/article-tags' => '创建文章标签',
        'PUT@admin/article-tags/*' => '更新文章标签',
        'DELETE@admin/article-tags/*' => '删除文章标签',
        
        // 文章相关
        'POST@admin/articles' => '创建文章',
        'PUT@admin/articles/*' => '更新文章',
        'DELETE@admin/articles/*' => '删除文章',
        'POST@admin/articles/*/publish' => '发布文章',
        'POST@admin/articles/*/unpublish' => '下架文章',
        'POST@admin/articles/*/top' => '置顶文章',
        'POST@admin/articles/*/untop' => '取消置顶',
        
        // 系统配置相关
        'POST@admin/settings' => '更新系统配置',
        'POST@admin/settings/clear-cache' => '清除系统缓存',
        
        // 其他敏感操作
        'POST@admin/*/batch-delete' => '批量删除操作',
        'POST@admin/*/import' => '数据导入操作',
        'POST@admin/*/export' => '数据导出操作',
    ];
    
    public function process(Request $request, callable $handler): Response
    {
        // 如果在排除列表中，直接放行
        if ($this->inExceptArray($request)) {
            return $handler($request);
        }
        
        // 记录请求开始时间
        $start = microtime(true);
        
        // 获取当前登录管理员
        $admin = $request->session()->get('admin');
        if (!$admin) {
            return $handler($request);
        }
        
        try {
            // 执行实际的请求
            $response = $handler($request);
            
            // 获取路由信息
            $path = $request->path();
            $method = $request->method();
            $pathInfo = explode('/', trim($path, '/'));
            
            // 检查是否是敏感操作
            $key = $method . '@' . $path;
            $isSensitive = $this->isSensitiveOperation($key);
            
            // 如果是敏感操作或者操作失败，记录日志
            if ($isSensitive || $response->getStatusCode() !== 200) {
                // 记录日志
                AdminOperationLogModel::create([
                    'admin_id' => $admin['id'],
                    'module' => $pathInfo[1] ?? '',  // 模块名
                    'action' => $pathInfo[2] ?? '',  // 操作方法
                    'method' => $method,
                    'url' => $request->url(),
                    'params' => $this->formatParams($request),
                    'ip' => $request->getRealIp(),
                    'user_agent' => $request->header('user-agent'),
                    'description' => $this->getDescription($request),
                    'status' => $response->getStatusCode() === 200 ? 1 : 0,
                ]);
            }
            
            return $response;
            
        } catch (\Throwable $e) {
            // 记录失败日志
            AdminOperationLogModel::create([
                'admin_id' => $admin['id'],
                'module' => $pathInfo[1] ?? '',
                'action' => $pathInfo[2] ?? '',
                'method' => $request->method(),
                'url' => $request->url(),
                'params' => $this->formatParams($request),
                'ip' => $request->getRealIp(),
                'user_agent' => $request->header('user-agent'),
                'description' => $e->getMessage(),
                'status' => 0,
            ]);
            
            throw $e;
        }
    }
    
    /**
     * 检查是否在排除列表中
     */
    protected function inExceptArray($request): bool
    {
        foreach ($this->except as $except) {
            if ($except !== '/') {
                $except = trim($except, '/');
            }
            
            if ($request->is($except)) {
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * 检查是否是敏感操作
     */
    protected function isSensitiveOperation($key): bool
    {
        // 检查完全匹配
        if (isset($this->sensitiveOperations[$key])) {
            return true;
        }
        
        // 检查通配符匹配
        foreach ($this->sensitiveOperations as $pattern => $description) {
            if (strpos($pattern, '*') !== false) {
                $pattern = str_replace('*', '.*', $pattern);
                if (preg_match('#^' . $pattern . '$#', $key)) {
                    return true;
                }
            }
        }
        
        return false;
    }
    
    /**
     * 格式化请求参数
     */
    protected function formatParams($request): array
    {
        $params = $request->all();
        
        // 过滤敏感信息
        $sensitiveFields = [
            'password',
            'password_confirmation',
            'old_password',
            'new_password',
            'token',
            'access_token',
            'refresh_token',
            'secret',
            'api_key',
        ];
        
        foreach ($sensitiveFields as $field) {
            if (isset($params[$field])) {
                $params[$field] = '******';
            }
        }
        
        return $params;
    }
    
    /**
     * 获取操作描述
     */
    protected function getDescription($request): string
    {
        $path = $request->path();
        $method = $request->method();
        $key = $method . '@' . $path;
        
        // 检查完全匹配
        if (isset($this->sensitiveOperations[$key])) {
            return $this->sensitiveOperations[$key];
        }
        
        // 检查通配符匹配
        foreach ($this->sensitiveOperations as $pattern => $description) {
            if (strpos($pattern, '*') !== false) {
                $pattern = str_replace('*', '.*', $pattern);
                if (preg_match('#^' . $pattern . '$#', $key)) {
                    // 替换描述中的通配符
                    $pathParts = explode('/', $path);
                    $patternParts = explode('/', str_replace('*', '(\d+)', $pattern));
                    foreach ($pathParts as $i => $part) {
                        if (isset($patternParts[$i]) && strpos($patternParts[$i], '(\d+)') !== false) {
                            $description = str_replace('*', $part, $description);
                        }
                    }
                    return $description;
                }
            }
        }
        
        return '未知操作';
    }
} 